package com.devops.admin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.devops.admin.mapper.DOSResourceMapper;
import com.devops.admin.model.*;
import com.devops.admin.po.DOSBindResourcePo;
import com.devops.admin.po.DOSResourcePo;
import com.devops.admin.po.DOSResourceProject;
import com.devops.admin.service.DOSResourceProjectRelationService;
import com.devops.admin.service.DOSResourceService;
import com.devops.admin.util.Assert;
import com.devops.admin.util.DatabaseConnectionTestUtil;
import com.devops.admin.util.TimeUtil;
import com.devops.admin.vo.DOSPageVo;
import com.devops.admin.vo.DOSResourceVo;
import com.devops.shiro.vm.BaseUserVM;
import org.apache.shiro.SecurityUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName DOSResourceService
 * @Description TODO
 * @Author hepingguo
 * @Date 2022/6/8 11:22
 * @Version 1.0
 **/
@Service
public class DOSResourceServiceImpl extends ServiceImpl<DOSResourceMapper, DOSResource> implements DOSResourceService {

    @Autowired
    private DOSResourceProjectRelationService dosResourceProjectRelationService;

    @Override
    public Boolean saveResource(DOSResource resource) {
        //校验用户
        checkUser();
        Assert.isTrue(null!=resource,"资源信息不能为空");
        Assert.isTrue(checkResourceUniqueness(resource),"不能重复添加");
        if (resource.isTestConnection()) {
            if (resource.getType() == 1 || (resource.getType() == 3 && resource.getSubType() == 8)) {
                boolean connection = DatabaseConnectionTestUtil.testConnection(resource);
                Assert.isTrue(connection, "资源连接不通，请检查资源信息!");
            }
        }
        //获取当前传入时间的所在天的最后的时分秒
        LocalDateTime expireTime = resource.getExpireTime();
        Date date = Date.from(expireTime.toInstant(ZoneOffset.of("+8")));
        LocalDateTime dateEnd = TimeUtil.getDateEnd(date);
        resource.setExpireTime(dateEnd);
        return this.save(resource);
    }

    @Override
    public Boolean updateResource(DOSResource resource) {

        //校验用户
        checkUser();
        Assert.isTrue(resource != null && resource.getId() >0,"资源信息id不能为空");
        Assert.isTrue(checkResourceUniqueness(resource),"资源信息重复");
        if (resource.getType() == 1 || (resource.getType() == 3 && resource.getSubType() == 8)){
            boolean connection = DatabaseConnectionTestUtil.testConnection(resource);
            Assert.isTrue(connection,"资源连接不通，请检查资源信息!");
        }
        //获取当前传入时间的所在天的最后的时分秒
        LocalDateTime expireTime = resource.getExpireTime();
        Date date = Date.from(expireTime.toInstant(ZoneOffset.of("+8")));
        LocalDateTime dateEnd = TimeUtil.getDateEnd(date);
        resource.setExpireTime(dateEnd);
        return this.updateById(resource);
    }

    @Override
    public Boolean removeResource(Integer resourceId) {

        //校验用户
        checkUser();

        LambdaQueryWrapper<DOSResourceProjectRelation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DOSResourceProjectRelation::getResourceId,resourceId);
        long count = dosResourceProjectRelationService.count(queryWrapper);
        Assert.isTrue(count==0,"资源已经绑定项目，无法删除");

        return this.removeById(resourceId);
    }

    @Override
    public TableResult<DOSResourcePo> queryResources(DOSResourceVo resource, DOSPageVo pageVo) {
        if (resource.getProjectId() == null || resource.getProjectId() == 0) {
            Assert.isTrue(resource != null, "查询条件不能为空");
        }
        Page<DOSResource> page = new Page<>(pageVo.getPageNum(), pageVo.getPageSize());
        TableResult<DOSResourcePo> tableResult = new TableResult<>();
        LambdaQueryWrapper<DOSResource> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DOSResource::getType,resource.getType());
        Page<DOSResource> resourcePage = baseMapper.selectPage(page, queryWrapper);
        if (CollectionUtil.isEmpty(resourcePage.getRecords())){

            return tableResult;
        }
        List<Integer> resourceIds = resourcePage.getRecords().stream().map(DOSResource::getId).distinct().collect(Collectors.toList());
        resource.setResourceIds(resourceIds);
        //分页查询资源信息
        List<DOSResourcePo> resources = baseMapper.selectResource(resource);
        List<DOSResourcePo> dosResourcePoList = getDosResourcePos(resources);

        //组装分页信息
        Pagination p = Pagination.builder().pageNum(page.getCurrent()).pageSize(page.getSize()).total(page.getTotal()).build();
        tableResult.setList(dosResourcePoList);
        tableResult.setPagination(p);

        return tableResult;
    }

    @Override
    public List<DOSResourcePo> queryResources(DOSResourceVo resource) {
        List<DOSResourcePo> resources = baseMapper.selectResource(resource);

        return getDosResourcePos(resources);
    }

    @Override
    public List<DOSBindResourcePo> getBindResource(Integer projectId, Integer type) {
        Assert.isTrue(projectId != null && projectId > 0,"项目id不能为空");
        List<DOSResourcePo> resources = baseMapper.getBindResource(projectId,type);
        resources.forEach(resource -> {
            String name = resource.getName() + "(" + resource.getTypeName() +
                    "/" + resource.getSubTypeName() + ")";
            resource.setName(name);
        });
        List<DOSBindResourcePo> bindResources = new ArrayList<>();
        DOSBindResourcePo bindResourcePo = DOSBindResourcePo.builder()
                .bingStatus(0).resources(new ArrayList<>()).build();
        bindResources.add(bindResourcePo);
        DOSBindResourcePo noBindResourcePo = DOSBindResourcePo.builder()
                .bingStatus(1).resources(new ArrayList<>()).build();
        bindResources.add(noBindResourcePo);

        if (CollectionUtil.isNotEmpty(resources)){
            Map<Integer, List<DOSResourcePo>> resourceMap = resources.stream()
                    .collect(Collectors.groupingBy(DOSResourcePo::getBindStatus));
            resourceMap.forEach((k,v) -> {
                DOSBindResourcePo bindResource = new DOSBindResourcePo();
                bindResource.setBingStatus(k);
                bindResource.setResources(new ArrayList<>());
                bindResources.remove(bindResource);
                bindResource.setResources(v);
                bindResources.add(bindResource);
            });
        }

        return bindResources.stream().sorted(Comparator.comparing(DOSBindResourcePo::getBingStatus)).collect(Collectors.toList());
    }

    @Override
    public List<DOSResource> getResourcesByType(Integer type) {
        LambdaQueryWrapper<DOSResource> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DOSResource::getType,type);

        return baseMapper.selectList(queryWrapper);
    }

    @Override
    public List<DOSResource> getRedisList() {
        return list(Wrappers.<DOSResource>lambdaQuery()
                .eq(DOSResource::getType,3)
                .eq(DOSResource::getSubType,8));
    }

    @Override
    public List<DOSResource> getDatabases(Integer type) {
        return list(Wrappers.<DOSResource>lambdaQuery()
                .eq(DOSResource::getType,1)
                .eq(DOSResource::getSubType,type));
    }

    /**
     * @Author heyabo
     * @Description 组装数据
     * @Date 15:55 2022/6/9
     * @Param [resources]
     * @return java.util.List<com.devops.admin.po.DOSResourcePo>
     **/
    @NotNull
    private List<DOSResourcePo> getDosResourcePos(List<DOSResourcePo> resources) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        resources.forEach(resource -> {
            LocalDateTime expireTime = resource.getExpireTime();
            if (expireTime != null) {
                String format = expireTime.format(df);
                resource.setExpireTimeStr(format);
            }
        });
        List<Integer> integers = resources.stream().map(DOSResource::getId).distinct().collect(Collectors.toList());
        Map<Integer, List<DOSResourcePo>> listMap = resources.stream().collect(Collectors.groupingBy(DOSResource::getId));

        List<DOSResourcePo> dosResourcePoList = new ArrayList<>();
        integers.forEach(resourceId -> {
            List<DOSResourcePo> dosResourcePos = listMap.get(resourceId);
            List<DOSResourceProject> dosResourceProjects = new ArrayList<>();
            dosResourcePos.forEach(dosResourcePo -> {
                if (dosResourcePo.getProjectId() != null && StrUtil.isNotBlank(dosResourcePo.getProjectName())){
                    DOSResourceProject dosResourceProject = new DOSResourceProject();
                    dosResourceProject.setProjectId(dosResourcePo.getProjectId());
                    dosResourceProject.setProjectName(dosResourcePo.getProjectName());
                    dosResourceProjects.add(dosResourceProject);
                }
            });

            DOSResourcePo dosResourcePo = dosResourcePos.get(0);
            dosResourcePo.setResourceProject(dosResourceProjects);
            dosResourcePoList.add(dosResourcePo);
        });
        return dosResourcePoList;
    }

    /**
     * @Author heyabo
     * @Description 检查资源在数据库是否已经存在
     * @Date 14:40 2022/6/8
     * @Param [resource]
     * @return java.lang.Boolean
     **/
    private boolean checkResourceUniqueness(DOSResource resource){
        LambdaQueryWrapper<DOSResource> queryWrapper = Wrappers.lambdaQuery();
        if (null != resource.getId() && resource.getId() > 0) {
            queryWrapper.ne(DOSResource::getId,resource.getId());
        }
        queryWrapper.eq(DOSResource::getName,resource.getName());
        //按照名字检查数据的唯一性
        return this.count(queryWrapper) == 0;
    }

    /**
     * @Author heyabo
     * @Description 校验用户信息
     * @Date 15:27 2022/6/8
     * @Param []
     * @return void
     **/
    private void checkUser(){
        BaseUserVM user = (BaseUserVM) SecurityUtils.getSubject().getPrincipal();
        Assert.isTrue(null!=user,"该用户未认证");
        Assert.isTrue(user.getAdminRole(),"没有操作的权限");
    }
}
